iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0

Table of Contents

  • prototype
  • 一些object method
  • 繼承
    • 一些物件原型的方法
      • 新增有原型的物件
      • 從物件檢視原型
      • 從原有物件設定原型
  • References

讓我們來看一下昨天最後一個使用到prototype的範例:

const contestant = {
  contestantId: 1,
  contestantName: "Alice",
}

const addNewItem = { fruit:'apple',};
Object.setPrototypeOf(contestant,addNewItem);

//新增原型之後
console.log(contestant);
//印出:
//{
//   contestantId: 1,
//   contestantName: 'Alice',

for(const key in contestant){
  console.log(key);
//印出:
// contestantId
// contestantName
// fruit
}

還記得for-in會連同原型一起被印出嗎?請觀察兩者之間的差異,是不是發現如果單獨印出contestant的值,並沒有fruit這個屬性,就好像是被隱形起來的內容。而今天就是要講一下prototype(原型)在做些什麽。

prototype

先來看看MDN在開頭如何說明:

Prototypes are the mechanism by which JavaScript objects inherit features from one another.

原型是JavaScript相互繼承功能的機制。

光是上面的話還是很難理解,來使用devtool創立一個物件,點開來看一下有什麽內容:

在上面創立一個物件之後,當我使用物件,從內容點開來就會發現有個[[Prototype]]能被點開來,其內容可由大家自行查閱。但這裡想提的是,object本身無論有沒有特別設置原型,在他的機制中原本就會預設一個給物件使用。

再來,原型本身就是一個物件,這個原型還會有自己的原型,直到找到null為止。比方我們以上面創建的object,使用.__proto__訪問器(accessor)來找他的原型:

會發現我們第一次用.__proto__找到object的原型,再往上找就是空的。

繼承

接著來看一下物件繼承是什麽樣子。
讓我們在範例中為原有物件加上原型:

const eligibility = {
  adult:true,
}

const contestant = {
  contestantId: 1,
  contestantName: "Alice",
  __proto__:eligibility
}

console.log(contestant.adult)//true

eligibilitycontestant的原型,而contestant繼承eligibility的屬性與方法,也就是說透過eligibility這個物件增加屬性與方法,contestant也能使用繼承過來的內容。

感受一下不同物件繼承同樣的原型:

const contestant1 = {
    contestantId: 1,
    contestantName: "Alice",
  __proto__:eligibility
}

const contestant2 = {
  contestantId: 2,
  contestantName: "Bob",
__proto__:eligibility
}

const contestant3 = {
  contestantId: 3,
  contestantName: "Charlie",
__proto__:eligibility
}

console.log(contestant1.adult);//true
console.log(contestant2.adult);//true
console.log(contestant3.adult);//true

我們在剛才為contestant物件設置eligibility的原型,那如果eligibility也有原型,來看看會怎樣:

const item = {
  upper:1,
}

const eligibility = {
    adult:true,
    __proto__:item,
  }
  
const contestant = {
    contestantId: 1,
    contestantName: "Alice",
  __proto__:eligibility
}

console.log(contestant.upper);//1
console.log(contestant.adult);//true
console.log(contestant.__proto__.__proto__);//{ upper: 1 }

可以發現,原型不僅能夠增加自己的原型,也能讓新繼承的物件使用原型所繼承的屬性或方法,一樣能透過.__proto與一些方法查找原型,這樣一個個連結的關係讓這些原型產生原型鍊(prototype chain)。

一些物件原型的方法

新增有原型的物件

我們可以使用Object.create()在一開始就設置物件的原型。

const eligibility = {
  adult:true,
}

const newContestant = Object.create(eligibility)
console.log(newContestant.adult)//true

從物件檢視原型

雖然上面使用.__proto__範例找原型的過程,但實際上只剩瀏覽器支持此用法,不推薦使用,如果想要找到object的原型,可以使用Object.getPrototypeOf()Reflect.getPrototypeOf()

const contestant = {
  contestantId: 1,
  contestantName: "Alice",
  hotpotFlavor: "Spicy Sichuan",
  hotpotIngredients: ["Beef slices", "Tofu", "Enoki mushrooms", "Napa cabbage"],
  summarizeCooking: function () {
    return "Balancing spicy Sichuan flavor with tender beef, tofu, and crunchy cabbage. Pairing with fragrant jasmine tea enhances the experience.";
  },
}

const addNewItem = { fruit:'apple',};
Object.setPrototypeOf(contestant,addNewItem);

//新增原型之後,透過上述兩個方式取得原型物件
console.log(Object.getPrototypeOf(contestant));//{ fruit: 'apple' }
console.log(Reflect.getPrototypeOf(contestant));//{ fruit: 'apple' }

從原有物件設定原型

雖然在最一開始已經使用過Object.setPrototypeOf()的使用,但讓我們再一次不透過.__proto__來範例。

const eligibility = {
    adult:true,
    __proto__:item,
  }
  
const contestant = {
    contestantId: 1,
    contestantName: "Alice",
  __proto__:eligibility
}

Object.setPrototypeOf(contestant,eligibility)
console.log(Object.getPrototypeOf(contestant));

上面有提到檢視物件時可以用Reflect.getPrototypeOf()看到原型的內容,但Reflect.setPrototypeOf()不一樣的是,在使用Reflect.setPrototypeOf()設置原型時,他會回傳一個boolean值。

console.log(Object.setPrototypeOf(contestant,eligibility));
//回傳物件本身:{ contestantId: 1, contestantName: 'Alice' }
console.log(Reflect.setPrototypeOf(contestant,eligibility));
//回傳物件成功與否:true

References

Day15-Object.create() 介紹
15. [JS] 什麼是原型鏈?
How can I read ‘native code’ JavaScript functions?

原型基礎物件導向


  • 忍者:JavaScript開發技巧探秘第二版(第七章)

  • MDN

  1. Object prototypes
  2. Object.prototype.proto
  3. Object.create()
  4. Object.getPrototypeOf()
  5. Reflect.getPrototypeOf()
  6. Object.setPrototypeOf()
  7. Reflect.setPrototypeOf()
  • Javascript Info
  1. Prototypal inheritance
  2. Prototype methods, objects without proto

上一篇
〈Day5〉遍歷物件的for-in
下一篇
〈Day7〉建構函式的原型與new運算子
系列文
廚藝不精也可以,給自己做一份Javascript小火鍋30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言